package cn.amaake.magicplugin.nacos.util;

import cn.amaake.magicplugin.nacos.config.NacosConfig;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.spring.core.env.NacosPropertySource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.StandardEnvironment;

import java.util.*;


public class NacosConfigLoader {

    private final Logger logger = LoggerFactory.getLogger(NacosConfigLoader.class);

    private final NacosConfig nacosConfigProperties;
    private final Properties globalProperties;
    private final ConfigurableEnvironment environment;
    public NacosConfigLoader(NacosConfig nacosConfigProperties, ConfigurableEnvironment environment) {
        this.nacosConfigProperties = nacosConfigProperties;
        this.environment = environment;
        globalProperties=buildGlobalNacosProperties();
    }

    public Properties buildGlobalNacosProperties() {
        Properties properties = new Properties();
        processPropertiesData(properties,environment,nacosConfigProperties.getServerAddr(),"serverAddr");
        processPropertiesData(properties,environment,nacosConfigProperties.getDataId(),"dataId");
        processPropertiesData(properties,environment,nacosConfigProperties.getGroup(),"group");
        return properties;
    }

    private void processPropertiesData(Properties properties, Environment environment, String keyword, String key) {
        if (StringUtils.isNotBlank(keyword)) {
            properties.put(key ,environment.resolvePlaceholders(keyword));
        }
    }

    public void loadConfig() throws NacosException {
        MutablePropertySources mutablePropertySources = environment.getPropertySources();

        List<NacosPropertySource> sources = reqGlobalNacosConfig(globalProperties, nacosConfigProperties.getType());

        if (nacosConfigProperties.isRemoteFirst()) {
            for (ListIterator<NacosPropertySource> itr = sources.listIterator(sources.size()); itr.hasPrevious();) {
                mutablePropertySources.addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, itr.previous());
            }
        } else {
            for (NacosPropertySource propertySource : sources) {
                mutablePropertySources.addLast(propertySource);
            }
        }
    }

    private List<NacosPropertySource> reqGlobalNacosConfig(Properties globalProperties, ConfigType type) throws NacosException {
        List<String> dataIds = new ArrayList<>();
        // Loads all data-id information into the list in the list
        dataIds.add(nacosConfigProperties.getDataId());
        return new ArrayList<>(Arrays.asList(reqNacosConfig(globalProperties,dataIds.toArray(new String[0]), nacosConfigProperties.getGroup(), type)));
    }

    private NacosPropertySource[] reqNacosConfig(Properties configProperties,String[] dataIds, String groupId, ConfigType type) throws NacosException {
        NacosPropertySource[] propertySources = new NacosPropertySource[dataIds.length];
        for (int i = 0; i < dataIds.length; i++) {
            if (!StringUtils.hasLength(dataIds[i])) {
                continue;
            }
            // Remove excess Spaces
            String dataId = environment.resolvePlaceholders(dataIds[i].trim());
            String serverAddr = nacosConfigProperties.getServerAddr();
            Properties properties = new Properties();
            properties.put("serverAddr", serverAddr);
            if (nacosConfigProperties.isEnabledAuth()){
                properties.put("username",nacosConfigProperties.getUsername());
                properties.put("password",nacosConfigProperties.getPassword());
            }
            ConfigService configService = NacosFactory.createConfigService(properties);
            String config = configService.getConfig(dataId, groupId, nacosConfigProperties.getTimeout());
            NacosPropertySource nacosPropertySource = new NacosPropertySource(dataId, groupId,buildDefaultPropertySourceName(dataId, groupId, configProperties),config, type.getType());
            nacosPropertySource.setDataId(dataId);
            nacosPropertySource.setType(type.getType());
            nacosPropertySource.setGroupId(groupId);
            logger.info("load config from nacos, data-id is : {}, group is : {}",nacosPropertySource.getDataId(), nacosPropertySource.getGroupId());
            propertySources[i] = nacosPropertySource;
        }
        return propertySources;
    }

    public static String buildDefaultPropertySourceName(String dataId, String groupId, Map<?, ?> properties) {
        return build(dataId, groupId, identify(properties));
    }

    public static String identify(Map<?, ?> properties) {
        String serverAddr = (String)properties.get("serverAddr");
        String dataId = (String)properties.get("dataId");
        String group = (String)properties.get("group");
        return build(serverAddr, dataId, group);
    }

    private static String build(Object... values) {
        StringBuilder stringBuilder = new StringBuilder();
        Object[] var2 = values;
        int var3 = values.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Object value = var2[var4];
            String stringValue = value == null ? null : String.valueOf(value);
            if (org.springframework.util.StringUtils.hasText(stringValue)) {
                stringBuilder.append(stringValue);
            }

            stringBuilder.append("|");
        }

        return stringBuilder.toString();
    }

}